package net.wangds.jwt.comp;

import net.wangds.utils.JsonUtils;
import io.jsonwebtoken.*;
import net.wangds.log.helper.LogHelper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class JwtTokenComp {

    /**
     * JWT签名加密key.
     */

    private String secret;

    /**
     * http认证头方法前缀.
     */
    private String httpAuthMethod;

    /**
     * 权限参数头
     */
    private String customInfos;

    /**
     * token有效期
     */
    private Long tokenExpireMs;

    public JwtTokenComp(
            @Value("${jwt.secret:mySecret}")String secret,
            @Value("${jwt.httpAuthMethod:Bearer}")String httpAuthMethod,
            @Value("${jwt.customInfos:role}")String customInfos,
            //3600000L*8;//token有效期为8小时
            @Value("${jwt.tokenExpireMs:28800000}")long tokenExpireMs

    ) {
        this.secret = secret;
        this.httpAuthMethod = httpAuthMethod;
        this.customInfos = customInfos;
        this.tokenExpireMs = tokenExpireMs;
    }

    //生成token
    public String generateAccessToken(UserDetails userDetails, String ip) {
        UserDetails user =  userDetails;
        LogHelper.debug(()->"生成token:"+user+","+JsonUtils.toJsonStr(user)+",ip:"+ip);
        //登陆成功生成JWT
        return Jwts.builder()
                //主题 放入用户名
                .setSubject(user.getUsername())
                //放入ip
                .setId(ip)
                //自定义属性 放入用户拥有权限
                .claim(customInfos, JsonUtils.toJsonStr(user.getAuthorities()))
                //失效时间
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpireMs))
                //签名算法和密钥
                .signWith(SignatureAlgorithm.HS512, secret)
                //压缩token
                .compressWith(CompressionCodecs.DEFLATE)
                .compact();
    }

    //获取存入token中的数据
    public Claims getClaims(String accessToken) {
        Claims claims;
        if (!accessToken.startsWith(httpAuthMethod)) {
            //token被修改
            throw new AuthenticationServiceException("令牌被修改");
        }
        try {
            claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(StringUtils.trim(StringUtils.removeStart(accessToken,httpAuthMethod)))
                    .getBody();
        } catch (ExpiredJwtException e) {
            //token过期
            throw new AuthenticationServiceException("令牌过期");
        } catch (SignatureException | MalformedJwtException e) {
            //token被修改
            throw new AuthenticationServiceException("身份认证令牌异常");
        }
        return claims;
    }
}
